package rexsee.multimedia;

import java.io.File;

import rexsee.core.browser.Browser;
import rexsee.core.browser.clazz.JavascriptInterface;
import rexsee.core.utilities.Utilities;
import android.hardware.Camera;
import android.hardware.Camera.AutoFocusCallback;
import android.view.SurfaceHolder;

public class RexseeImageCapture implements JavascriptInterface {

	public static final String INTERFACE_NAME = "ImageCapture";
	@Override
	public String getInterfaceName() {
		return mBrowser.application.resources.prefix + INTERFACE_NAME;
	}
	@Override
	public JavascriptInterface getInheritInterface(Browser childBrowser) {
		return this;
	}
	@Override
	public JavascriptInterface getNewInterface(Browser childBrowser) {
		return new RexseeImageCapture(childBrowser);
	}

	public static final String EVENT_ONIMAGECAPTUREFINISHED = "onImageCaptureFinished";

	private final Browser mBrowser;
	private SurfaceDialog mSurfaceDialog = null;
	private Camera mCamera = null;
	private final ImageCaptureArguments mArguments;

	public RexseeImageCapture(Browser browser) {
		mBrowser = browser;
		mBrowser.eventList.add(EVENT_ONIMAGECAPTUREFINISHED);
		mArguments = new ImageCaptureArguments();
	}

	//JavaScript Interface
	public boolean start(final String path) {
		return start(path, false);
	}
	public boolean start(final String path, final boolean autoFocus) {
		File file = Utilities.prepareWriteFile(path);
		if (file == null) {
			if (mBrowser != null) mBrowser.exception(getInterfaceName(), "Invalid target file path.");
			return false;
		}
		final RexseeCameraPreview preview = RexseeCameraPreview.getPreview(mBrowser);
		if (preview != null) {
			Camera camera = preview.getCamera();
			try {
				mArguments.setCamera(camera);
			} catch (Exception e) {
			}
			if (autoFocus) {
				camera.autoFocus(new AutoFocusCallback() {
					@Override
					public void onAutoFocus(boolean success, Camera camera) {
						camera.takePicture(null, null, new Camera.PictureCallback() {
							@Override
							public void onPictureTaken(byte[] data, Camera camera) {
								if (data != null) {
									Utilities.putContent(path, data);
									mBrowser.eventList.run(EVENT_ONIMAGECAPTUREFINISHED, new String[]{"true", path});
								} else {
									mBrowser.eventList.run(EVENT_ONIMAGECAPTUREFINISHED, new String[]{"false", ""});
								}
								camera.startPreview();
							}
						});
					}
				});
			} else {
				camera.takePicture(null, null, new Camera.PictureCallback() {
					@Override
					public void onPictureTaken(byte[] data, Camera camera) {
						try {
							if (data != null) {
								Utilities.putContent(path, data);
								mBrowser.eventList.run(EVENT_ONIMAGECAPTUREFINISHED, new String[]{"true", path});
							} else {
								mBrowser.eventList.run(EVENT_ONIMAGECAPTUREFINISHED, new String[]{"false", ""});
							}
							camera.startPreview();
						} catch (Exception e) {
							if (mBrowser != null) mBrowser.exception(getInterfaceName(), e);
						}
					}
				});
			}
			return true;
		} else {
			try {
				SurfaceHolder.Callback callback = new SurfaceHolder.Callback() {
					@Override
					public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
					}
					@Override
					public void surfaceCreated(SurfaceHolder holder) {
						try {
							mCamera = Camera.open(); //Camera.open(index) to open different camera device since API 9
							try {
								mArguments.setCamera(mCamera);
							} catch (Exception e) {
							}
							mCamera.setErrorCallback(new Camera.ErrorCallback() {
								@Override
								public void onError(int error, Camera camera) {
									String errorString;
									switch (error) {
										case Camera.CAMERA_ERROR_SERVER_DIED :
											errorString = "CAMERA_ERROR_SERVER_DIED";
											break;
										default :
											errorString = "CAMERA_ERROR_UNKNOWN";
											break;
									}
									mBrowser.exception(getInterfaceName(), errorString);
								}
							});
							mCamera.setPreviewDisplay(holder);
							mCamera.startPreview();
							if (autoFocus) {
								mCamera.autoFocus(new AutoFocusCallback() {
									@Override
									public void onAutoFocus(boolean success, Camera camera) {
										camera.takePicture(null, null, new Camera.PictureCallback() {
											@Override
											public void onPictureTaken(byte[] data, Camera camera) {
												if (data != null) {
													Utilities.putContent(path, data);
													mBrowser.eventList.run(EVENT_ONIMAGECAPTUREFINISHED, new String[]{"true", path});
												} else {
													mBrowser.eventList.run(EVENT_ONIMAGECAPTUREFINISHED, new String[]{"false", ""});
												}
												if (mSurfaceDialog != null) {
													mSurfaceDialog.dismiss();
													mSurfaceDialog = null;
												}
											}
										});
									}
								});

							} else {
								mCamera.takePicture(null, null, new Camera.PictureCallback() {
									@Override
									public void onPictureTaken(byte[] data, Camera camera) {
										if (data != null) {
											Utilities.putContent(path, data);
											mBrowser.eventList.run(EVENT_ONIMAGECAPTUREFINISHED, new String[]{"true", path});
										} else {
											mBrowser.eventList.run(EVENT_ONIMAGECAPTUREFINISHED, new String[]{"false", ""});
										}
										if (mSurfaceDialog != null) {
											mSurfaceDialog.dismiss();
											mSurfaceDialog = null;
										}
									}
								});
							}
						} catch (Exception e) {
							if (mBrowser != null) mBrowser.exception(getInterfaceName(), e);
						}
					}
					@Override
					public void surfaceDestroyed(SurfaceHolder holder) {
						if (mCamera != null) {
							try {
								mCamera.stopPreview();
								mCamera.release();
							} catch (Exception e) {
							}
						}
						mCamera = null;
					}
				};
				mSurfaceDialog = new SurfaceDialog(mBrowser, "window-dim-amount:0;window-modeless:true;window-cancelable:false;width:1px;height:1px;border-width:0px;");
				mSurfaceDialog.start(callback);
				return true;
			} catch (Exception e) {
				if (mBrowser != null) mBrowser.exception(getInterfaceName(), e);
				return false;
			}
		}
	}

	public String getArguments() {
		return mArguments.toString();
	}
	public void setArguments(String arguments) {
		mArguments.parseArguments(arguments);
	}

}
